

#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "udpClient.h"

#define MAX_MSG 100
// 2 caractères pour les codes ASCII '\n' et '\0'
#define MSG_ARRAY_SIZE (MAX_MSG+2)


// Utilisation d'une constante x dans la définition
// du format de saisie
#define str(x) # x
#define xstr(x) str(x)

int udpClientTest(){
    int ecoute ;
    struct sockaddr_in adresse;
    struct hostent *serveur;

    serveur = hostUdpClient();
    if( 0 > ( ecoute = socketUdpClient() ) ){
        exit(EXIT_FAILURE);
    }

    adresse = sockaddrUdpClient();
    /*
       if ( 0 > ( ecouteUdpClient( ecoute, &adresse) ) ) {
       exit(EXIT_FAILURE);
       }*/

    if ( 0 > (  attenteUdpClient(ecoute, &adresse) ) ) {
        exit(EXIT_FAILURE);


    }
    exit(EXIT_SUCCESS);
}

struct hostent * hostUdpClient()
{
    struct hostent *host;
    host = gethostbyname("localhost");
    if (host == NULL) {
        fprintf(stderr, "Problème dans l'interprétation des informations d'hôte : %s\n", "localhost");
        exit(EXIT_FAILURE);
    }
    return host;
}
/**
 * Création de la socket d'écoute 
 */
int socketUdpClient(){
    int s;

    s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);

    if ( 0 > socket ){
        fprintf(stderr, "ERREUR : socketUdpClient()\n");
        return -1;
    }
    fprintf(stdout, "Création du socket : OK.\n");
    return s;
}

/**
 * initialisation de l'adresse
 */
struct sockaddr_in sockaddrUdpClient(struct hostent *serveur){
    struct sockaddr_in adresse;
    adresse.sin_family = serveur->h_addrtype;
    memcpy((char*) &adresse.sin_addr.s_addr, 
            serveur->h_addr_list[0], serveur->h_length);
    adresse.sin_port = htons((unsigned short int)4200); 
    fprintf(stdout, "Initialisation de l'adresse : OK.\n");
    return adresse;
}

/**
 * ecoute du socket
 */
int ecouteUdpClient(int socket, struct sockaddr_in * adresse )
{
    if(0 > ( bind( socket, (struct sockaddr * ) adresse, sizeof(struct sockaddr_in) ) ) ){
        fprintf(stderr, "ERREUR : Echec de liaison du socket en écoute\n");
        return -1;
    }
    fprintf(stdout, "Ecoute du socket : OK.\n");
    return 0;
}

/**
 * attente requete et réponse
 */
int attenteUdpClient(int socket, struct sockaddr_in * serverAddress){
    char msg[MSG_ARRAY_SIZE];
    int tailleMessage;
    struct timeval timeVal;
    fd_set readSet;

    fprintf(stdout, "Attente d'un message client en udp...\n");


    puts("Saisie du message : ");
    memset(msg, 0x0, MSG_ARRAY_SIZE);  // Mise à zéro du tampon

    // si ce qui est rentré& en entré dépace les MAX_MSG caractères drop
    scanf(" %"xstr(MAX_MSG)"[^\n]%*c", msg);

    while(strcmp(msg, "."))
    {
        if ( 0 < (tailleMessage = strlen(msg)) ){

            // Envoi de la ligne au serveur
            if (sendto(socket, msg, tailleMessage, 0,
                        (struct sockaddr *) &serverAddress,
                        sizeof(serverAddress)) < 0) {
                fputs("Émission du message impossible", stderr);
                close(socket);
                exit(EXIT_FAILURE);
            }

            // Attente de la réponse pendant une seconde.
            FD_ZERO(&readSet);
            FD_SET(socket, &readSet);
            timeVal.tv_sec = 1;
            timeVal.tv_usec = 0;

            if (select(socket+1, &readSet, NULL, NULL, &timeVal)) {
                // Lecture de la ligne modifiée par le serveur.
                memset(msg, 0x0, MSG_ARRAY_SIZE);  // Mise à zéro du tampon
                if (recv(socket, msg, MAX_MSG, 0) < 0) {
                    fputs("Aucune réponse du serveur ?", stderr);
                    close(socket);
                    exit(EXIT_FAILURE);
                }

                printf("Message traité : %s\n", msg);
            }
            else {
                puts("** Le serveur n'a répondu dans la seconde.");
            }
        }
        // Invite de commande pour l'utilisateur et lecture des caractères jusqu'à la
        // limite MAX_MSG. Puis suppression du saut de ligne en mémoire tampon.
        // Comme ci-dessus.
        puts("Saisie du message : ");
        memset(msg, 0x0, MSG_ARRAY_SIZE);  // Mise à zéro du tampon
        scanf(" %"xstr(MAX_MSG)"[^\n]%*c", msg);
    }

    close(socket);
    return 0;
}
